using Quartz;
using Vin.Event;
using Vin.Extension.Framework.Quartz.Entities;
using Vin.Extension.Framework.Quartz.EventArgs;
using Vin.Extension.Framework.Quartz.Listener;
using Vin.Extension.Framework.Quartz.ServiceInterface;
using Vin.Extension.Quartz.Models;
using Vin.Extension.Quartz.Service;
using Vin.Extension.SqlSugar.EventArgs;
using Vin.Tool.AspNetCore.Service;
using Vin.Tool.AspNetCore.Singleton;
using Vin.Tool.Attributes;
using Vin.Tool.Core.AssemblyCategory;
using Vin.Tool.Core.AssertCategory;
using Vin.Tool.Core.BasicTypeCategory;

namespace Vin.Extension.Framework.Quartz.BackgroundServices;

public class RegisterListenerBackgroundService : VinEventBackgroundService<VinSqlSugarInitEventArg>
{
    [Inject] private readonly ISchedulerFactory _schedulerFactory = null!;

    public RegisterListenerBackgroundService()
    {
        // 注册事件
        VinEventManager.Register<VinStartJobEventArg>(AddJobAsync);
        VinEventManager.Register<VinRemoveJobEventArg>(RemoveJobAsync);
    }

    protected override async Task RunAsync(CancellationToken stoppingToken)
    {
        // 加载未完成的任务
        await LoadJobAsync();
    }

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        // 注册监听器
        var scheduler = await _schedulerFactory.GetScheduler(stoppingToken);
        scheduler.ListenerManager.AddJobListener(new VinJobListener());
        await base.ExecuteAsync(stoppingToken);
    }

    #region 私有方法

    private async Task LoadJobAsync()
    {
        var jobService = VinApp.GetRequiredServiceByHttpContext<ISysJobService>();
        var jobs = await jobService.RunningListAsync();
        foreach (var job in jobs)
        {
            await AddJobAsync(this, new VinStartJobEventArg(job.Id!.Value) { Job = job });
            // TODO:有一个bug，当多个任务时间是相同的情况下，导致有的任务没有被执行
            await Task.Delay(100);
        }
    }

    #endregion

    #region 事件

    /// <summary>
    /// 添加（启动）任务
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="arg"></param>
    private async Task AddJobAsync(object? sender, VinEventArgs arg)
    {
        if (arg is VinStartJobEventArg jobArg)
        {
            var jobService = VinApp.GetRequiredServiceByHttpContext<ISysJobService>();
            var vinTaskService = VinApp.GetRequiredServiceByHttpContext<VinTaskService>();
            var job = jobArg.Job == null ? await jobService.QueryAsync(jobArg.JobId) : jobArg.Job;
            if (job != null)
            {
                // 添加任务
                var parameters = job.Parameters.Where(m => m.Key.IsNotNullOrEmpty())
                    .ToDictionary(x => x.Key!, x => (object)x.Value!);
                var taskInfo = new TaskInfo(job.Id.ToString()!, job.Name!, job.GroupId.ToString()!, parameters);
                taskInfo.StartTime = job.StartTime.HasValue && job.StartTime > 0
                    ? job.StartTime.Value.ToDateTime(false)
                    : null;
                taskInfo.EndTime = job.EndTime.HasValue && job.EndTime > 0 ? job.EndTime.Value.ToDateTime(false) : null;
                taskInfo.IsStartNow = job.FirstExecute;

                taskInfo.TaskInfoType = (TaskInfoType)job.ExecuteType!;
                if (job.ExecuteType == JobExecuteType.Generics)
                {
                    // 泛型任务
                    var type = AssemblyTool.GetVinTypes.FirstOrDefault(m => m.FullName == job.ClassName);
                    taskInfo.JobType = type;
                }
                else
                {
                    taskInfo.AssemblyPath = job.AssemblyPath;
                    taskInfo.AssemblyName = job.AssemblyName;
                    taskInfo.ClassName = job.ClassName;
                }

                // 触发器
                taskInfo.TriggerType = (TriggerType)job.TriggerType!;
                taskInfo.LoopType = (LoopType)job.LoopType!;
                taskInfo.LoopCount = (job.LoopCount - job.CompletedLoopCount - 1) ?? 0;
                if (taskInfo.LoopCount < 0) taskInfo.LoopCount = 0;

                taskInfo.IntervalType = (IntervalType)job.IntervalType!;
                taskInfo.Interval = job.IntervalValue ?? 0;

                taskInfo.CronExpression = job.Cron;

                // 添加任务
                await vinTaskService.AddJobTask(taskInfo);
            }
        }
    }

    /// <summary>
    /// 移除(停止)任务
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="arg"></param>
    private async Task RemoveJobAsync(object? sender, VinEventArgs arg)
    {
        if (arg is VinRemoveJobEventArg jobArg)
        {
            // var jobService = VinApp.GetRequiredServiceByHttpContext<ISysJobService>();
            var vinTaskService = VinApp.GetRequiredServiceByHttpContext<VinTaskService>();
            // var job = await jobService.QueryAsync(jobArg.JobId);
            // 删除任务
            await vinTaskService.RemoveJobTask(jobArg.JobId.ToString(), jobArg.GroupId.ToString());
        }
    }

    #endregion
}